package handler

import (
	"bufio"
	"context"
	"github.com/gin-gonic/gin"
	"go-devops/common"
	"go-devops/domain/dto"
	"go-devops/domain/model"
	"go-devops/domain/vo"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"sync"
)

var contextMap = model.NewContextMap()
var TaskMap = model.NewTaskMap()
var taskLock sync.Mutex

func TaskNamespaceList(c *gin.Context) {
	list, err := model.GetTaskNamespaceList()
	if err != nil {
		common.BizError(c, "查询失败")
		return
	}
	common.OKData(c, list)
}

func AddTaskNamespace(c *gin.Context) {
	var addNamespace dto.AddNamespaceDTO
	if err := c.ShouldBindJSON(&addNamespace); err != nil {
		common.BizError(c, err.Error())
		return
	}

	count, err := model.GetTaskNamespaceCount(addNamespace.Name)
	if err != nil {
		common.BizError(c, "添加失败")
		return
	}

	if count > 0 {
		common.BizError(c, "命名空间已存在，不能重复添加")
		return
	}

	taskNamespace := &model.TaskNamespace{
		Id:   common.NewUUID(),
		Name: addNamespace.Name,
	}

	if err := model.AddTaskNamespace(taskNamespace); err != nil {
		common.BizError(c, "添加失败")
		return
	}

	common.OKData(c, taskNamespace)
}

func DeleteNamespace(c *gin.Context) {
	id := c.Query("id")
	if len(id) <= 0 {
		common.Fail(c, common.ErrParam)
		return
	}

	count, err := model.QueryTaskCountByNamespace(id)
	if err != nil {
		common.BizError(c, "删除失败")
		return
	}

	if count > 0 {
		common.BizError(c, "该命名空间下存在流水线任务，不能删除")
		return
	}

	if err = model.DeleteTaskNamespace(id); err != nil {
		common.BizError(c, "删除失败")
		return
	}

	common.OK(c)
}

func TaskList(c *gin.Context) {
	var queryTask dto.QueryTask
	if err := c.ShouldBindJSON(&queryTask); err != nil {
		common.BizError(c, err.Error())
		return
	}

	// 查询任务列表
	taskList, err := model.QueryTaskListByNamespace(queryTask.Namespace)
	if err != nil {
		common.BizError(c, err.Error())
		return
	}

	resultList := make([]vo.TaskData, 0, 10)
	for _, task := range taskList {
		data := vo.TaskData{
			Id:        task.Id,
			Name:      task.Name,
			Namespace: task.Namespace,
			LastTime:  task.CreateTime,
		}

		if taskHis, err := model.QueryTaskHisByTaskId(task.Id); err == nil && taskHis != nil {
			data.LastTime = taskHis.CreateTime
			data.LastStatus = taskHis.Status
			data.LastMsg = taskHis.GitMsg
			data.LastBranch = taskHis.GitBranch
			data.LastOperator = taskHis.OptUser
		}
		resultList = append(resultList, data)
	}

	common.OKData(c, vo.PageResult(resultList))
}

func AddTask(c *gin.Context) {
	var addTask dto.AddTaskDTO
	if err := c.ShouldBindJSON(&addTask); err != nil {
		common.BizError(c, err.Error())
		return
	}

	count, err := model.QueryTaskCount(addTask.Name, addTask.Namespace)
	if err != nil {
		common.BizError(c, "添加流水线失败")
		return
	}

	if count > 0 {
		common.BizError(c, "流水线名称已存在")
		return
	}

	task := &model.Task{
		Name:      addTask.Name,
		Namespace: addTask.Namespace,
	}

	if addTask.Edit {
		if len(addTask.Id) <= 0 {
			common.BizError(c, "流水线id不能为空")
			return
		}
		task.Id = addTask.Id

		if err := model.UpdateTask(task); err != nil {
			common.BizError(c, "更新流水线失败")
			return
		}
	} else {
		task.Id = common.NewUUID()
		task.CreateTime = common.NowStr()

		if err := model.SaveTask(task); err != nil {
			common.BizError(c, "添加流水线失败")
			return
		}
	}
	common.OK(c)
}

func DeleteTask(c *gin.Context) {
	var deleteTask dto.DeleteTaskDTO
	if err := c.ShouldBindJSON(&deleteTask); err != nil {
		common.BizError(c, err.Error())
		return
	}

	list := make([]*model.Task, 0)
	for _, id := range deleteTask.List {
		list = append(list, &model.Task{Id: id})
	}
	if err := model.BatchDeleteTask(list); err != nil {
		common.BizError(c, "删除失败")
		return
	}

	for _, id := range deleteTask.List {
		workspace := common.Config.Node.Workspace
		os.RemoveAll(filepath.Join(workspace, id))
	}

	common.OK(c)
}

func TaskInfo(c *gin.Context) {
	id, ok := c.GetQuery("id")
	if !ok {
		common.BizError(c, "任务id不能为空")
		return
	}

	editParam, ok := c.GetQuery("edit")
	if !ok {
		common.BizError(c, "edit不能为空")
		return
	}
	edit, err := strconv.ParseBool(editParam)
	if err != nil {
		common.BizError(c, "edit参数类型错误")
		return
	}

	task, err := model.QueryTaskById(id)
	if err != nil || task == nil {
		common.BizError(c, "流水线数据不存在")
		return
	}

	result := &vo.TaskInfoVO{
		Id:          task.Id,
		Name:        task.Name,
		Namespace:   task.Namespace,
		Note:        task.Note,
		FlowData:    task.FlowData,
		CreateTime:  task.CreateTime,
		RunningFlag: false,
	}

	context := contextMap.Get(id)
	if context != nil && len(context.DataList) > 0 && !edit {
		result.TaskDataList = context.DataList
		result.RunningFlag = true
	} else if len(task.TaskData) > 0 {
		var list []dto.TaskData
		common.ParseJsonArray(task.TaskData, &list)
		result.TaskDataList = list
	}

	if taskNamespace, err := model.QueryTaskNamespaceById(task.Namespace); err == nil && taskNamespace != nil {
		result.NamespaceRel = taskNamespace.Name
	}
	common.OKData(c, result)
}

func SaveFlowData(c *gin.Context) {
	var taskInfo dto.TaskInfoDTO
	if err := c.ShouldBindJSON(&taskInfo); err != nil {
		common.BizError(c, err.Error())
		return
	}

	if taskOld, err := model.QueryTaskById(taskInfo.Id); err != nil || taskOld == nil {
		common.BizError(c, "数据异常，流水线不存在")
		return
	}

	task := &model.Task{
		Id:       taskInfo.Id,
		FlowData: taskInfo.FlowData,
	}

	if len(taskInfo.TaskDataList) > 0 {
		task.TaskData = common.JsonString(taskInfo.TaskDataList)
	}

	if err := model.UpdateTask(task); err != nil {
		common.BizError(c, "添加流程数据异常")
		return
	}
	common.OK(c)
}

func UpdateTaskData(c *gin.Context) {
	var taskInfo dto.TaskInfoDTO
	if err := c.ShouldBindJSON(&taskInfo); err != nil {
		common.BizError(c, err.Error())
		return
	}

	task := &model.Task{
		Id:       taskInfo.Id,
		TaskData: common.JsonString(taskInfo.TaskDataList),
	}

	if err := model.UpdateTask(task); err != nil {
		common.BizError(c, "更新数据异常")
		return
	}

	common.OK(c)
}

func RunTask(c *gin.Context) {
	username, _ := c.Get(common.USERNAME)
	taskId, ok := c.GetQuery("taskId")
	if !ok {
		common.BizError(c, "taskId不能为空")
		return
	}

	if lock := taskLock.TryLock(); !lock {
		common.BizError(c, "任务处理中，请等待执行完成!")
		return
	}
	defer taskLock.Unlock()

	task, err := model.QueryTaskById(taskId)
	if err != nil || task == nil {
		common.BizError(c, "数据异常，流水线不存在")
		return
	}

	if len(task.TaskData) <= 0 {
		common.BizError(c, "流程数据错误，请检查配置")
		return
	}

	var dataList []dto.TaskData
	common.ParseJsonArray(task.TaskData, &dataList)
	if len(dataList) <= 0 {
		common.BizError(c, "流程数据错误，请检查配置")
		return
	}

	if work := TaskMap.GetTaskWork(taskId); work != nil {
		common.BizError(c, "任务处理中，请等待执行完成!")
		return
	}

	batchId := task.BatchId + 1
	updateTask := &model.Task{
		Id:      taskId,
		BatchId: batchId,
	}
	if err := model.UpdateTask(updateTask); err != nil {
		common.BizError(c, "更新任务失败")
		return
	}

	logFile := buildLogFile(taskId, batchId)
	taskHis := &model.TaskHis{
		CreateTime: common.NowStr(),
		Status:     common.RUN,
		BatchId:    batchId,
		TaskId:     taskId,
		OptUser:    username.(string),
		LogFile:    logFile,
	}
	model.AddTaskHis(taskHis)

	ctx, cancel := context.WithCancel(context.Background())
	taskWork := &model.TaskWorker{
		TaskId:  taskId,
		Context: ctx,
		Cancel:  cancel,
	}
	TaskMap.SetTaskWork(taskId, taskWork)

	context := &dto.NodeContext{
		TaskId:   taskId,
		BatchId:  batchId,
		DataList: dataList,
		Context:  ctx,
		Cancel:   cancel,
		LogFile:  logFile,
	}
	contextMap.Set(taskId, context)

	go func(taskWork *model.TaskWorker, context *dto.NodeContext) {
		defer func() {
			taskWork.Cancel()
			log.Printf("任务：%s 完成", taskId)
			TaskMap.DelTaskWork(taskWork.TaskId)
			contextMap.Delete(taskWork.TaskId)
		}()
		for {
			select {
			case <-taskWork.Context.Done():
				return
			default:
				beforeFlow(context)
				for _, taskData := range context.DataList {
					if context.StopFlag {
						break
					}

					context.TaskData = taskData
					context.NodeType = taskData.TaskType
					handler := NodeFactory[taskData.TaskType]
					if err := handler.HandleNode(context); err != nil {
						errorHandle(context, err)
						return
					}
				}
				afterFlow(context)
				return
			}
		}
	}(taskWork, context)
	common.OK(c)
}

func buildLogFile(taskId string, batchId int64) string {
	workspace := common.Config.Node.Workspace
	return filepath.Join(workspace, taskId, "log", strconv.FormatInt(batchId, 10)+".log")
}

func getWorkspace(taskId string) string {
	workspace := common.Config.Node.Workspace
	targetWorkspace := filepath.Join(workspace, taskId)
	return targetWorkspace
}

func beforeFlow(nodeContext *dto.NodeContext) {
	// 创建工作目录
	targetWorkspace := getWorkspace(nodeContext.TaskId)
	os.MkdirAll(targetWorkspace, 0755)
	nodeContext.Workspace = targetWorkspace

	status := &dto.FlowStatusData{
		TaskId: nodeContext.TaskId,
		Status: true,
	}

	data := &model.MsgData{
		MsgType: model.FLOW,
		Data:    status,
		Time:    common.NowStr(),
	}
	TaskConnMap.Send(nodeContext, data)
}

func afterFlow(nodeContext *dto.NodeContext) {
	status := &dto.FlowStatusData{
		TaskId: nodeContext.TaskId,
		Status: false,
	}

	data := &model.MsgData{
		MsgType: model.FLOW,
		Data:    status,
		Time:    common.NowStr(),
	}
	TaskConnMap.Send(nodeContext, data)

	taskHis := &model.TaskHis{
		TaskId:  nodeContext.TaskId,
		BatchId: nodeContext.BatchId,
		Status:  common.SUCCESS,
	}
	model.UpdateTaskHisStatus(taskHis)
}

func errorHandle(nodeContext *dto.NodeContext, err error) {
	taskData := nodeContext.TaskData
	taskData.Status = common.ERROR

	status := &dto.NodeStatusData{
		Id:     taskData.Id,
		Status: taskData.Status,
	}
	data := &model.MsgData{
		MsgType: model.NODE,
		Data:    status,
		Time:    common.NowStr(),
	}
	TaskConnMap.Send(nodeContext, data)
	TaskConnMap.Send(nodeContext, model.MsgBuild(common.ERROR, true, taskData.Title+" 执行失败："+err.Error()))

	taskHis := &model.TaskHis{
		TaskId:  nodeContext.TaskId,
		BatchId: nodeContext.BatchId,
		Status:  common.ERROR,
	}
	model.UpdateTaskHisStatus(taskHis)
}

func StopTask(c *gin.Context) {
	taskId, ok := c.GetQuery("taskId")
	if !ok {
		common.BizError(c, "taskId不能为空")
		return
	}

	taskWork := TaskMap.GetTaskWork(taskId)
	log.Printf("taskWork:%+v\n", taskWork)
	if taskWork == nil {
		common.OK(c)
		return
	}

	taskWork.Cancel()
	if nodeContext := contextMap.Get(taskId); nodeContext != nil {
		handler := NodeFactory[nodeContext.NodeType]
		handler.Stop(nodeContext)
	}
	common.OK(c)
}

func HisList(c *gin.Context) {
	var taskHisDTO dto.QueryTaskHisDTO
	if err := c.ShouldBindJSON(&taskHisDTO); err != nil {
		common.BizError(c, err.Error())
		return
	}

	if taskHisDTO.PageNum <= 0 {
		taskHisDTO.PageNum = 1
	}

	if taskHisDTO.PageSize <= 0 {
		taskHisDTO.PageSize = 10
	}

	offset := taskHisDTO.PageSize * (taskHisDTO.PageNum - 1)
	limit := taskHisDTO.PageSize
	pageResult := &vo.Page{
		PageSize:   taskHisDTO.PageSize,
		PageNumber: taskHisDTO.PageNum,
	}
	list, total, err := model.QueryPageTaskHis(offset, limit, taskHisDTO.TaskId)
	if err == nil {
		pageResult.TotalRow = total
		pageResult.Records = list
	}
	common.OKData(c, pageResult)
}

func HisLog(c *gin.Context) {
	taskId, ok := c.GetQuery("taskId")
	if !ok {
		common.BizError(c, "taskId不能为空")
		return
	}

	batchId, ok := c.GetQuery("batchId")
	if !ok {
		common.BizError(c, "batchId不能为空")
		return
	}
	id, _ := strconv.ParseInt(batchId, 10, 64)
	taskHis, err := model.QueryTaskHisByBatchId(id, taskId)
	if err != nil || taskHis == nil || len(taskHis.LogFile) <= 0 {
		common.BizError(c, "获取日志失败")
		return
	}

	file, err := os.Open(taskHis.LogFile)
	if err != nil {
		common.BizError(c, "日志文件不存在")
		return
	}
	defer file.Close()

	list := make([]string, 0, 30)
	scanner := bufio.NewScanner(file)
	scanner.Buffer(make([]byte, 0, 30*1024*1024), 30*1024*1024)
	for scanner.Scan() {
		list = append(list, scanner.Text())
	}
	common.OKData(c, list)
}

func BranchList(c *gin.Context) {
	taskId, ok := c.GetQuery("taskId")
	if !ok {
		common.BizError(c, "taskId不能为空")
		return
	}

	task, err := model.QueryTaskById(taskId)
	if err != nil || task == nil {
		common.BizError(c, "数据异常，流水线不存在")
		return
	}

	if len(task.TaskData) <= 0 {
		common.BizError(c, "流程数据错误，请检查配置")
		return
	}

	var dataList []*dto.TaskData
	common.ParseJsonArray(task.TaskData, &dataList)
	if len(dataList) <= 0 {
		common.BizError(c, "流程数据错误，请检查配置")
		return
	}

	taskData := getGitNode(dataList)
	if taskData == nil {
		common.BizError(c, "git节点不存在，获取不到分支信息")
		return
	}

	workspace := getWorkspace(taskId)
	list, err := GetBranchList(taskData.Data, workspace, taskId)
	if err != nil {
		common.BizError(c, "获取分支失败")
		return
	}
	common.OKData(c, list)
}

func getGitNode(list []*dto.TaskData) *dto.TaskData {
	for _, data := range list {
		if common.GIT == data.TaskType {
			return data
		}
	}
	return nil
}

func SaveTemplate(c *gin.Context) {
	var taskTemplateDTO dto.TaskTemplateDTO
	if err := c.ShouldBindJSON(&taskTemplateDTO); err != nil {
		common.BizError(c, err.Error())
		return
	}

	taskTemplate := &model.TaskTemplate{
		Name:       taskTemplateDTO.Name,
		FlowData:   taskTemplateDTO.FlowData,
		CreateTime: common.NowStr(),
	}

	if err := model.SaveTaskTemplate(taskTemplate); err != nil {
		common.BizError(c, "保存模版失败")
		return
	}

	common.OK(c)
}

func DeleteTemplate(c *gin.Context) {
	id := c.Query("id")
	if len(id) <= 0 {
		common.BizError(c, "模版id不能为空")
		return
	}

	templateId, err := strconv.ParseInt(id, 10, 64)
	if err != nil {
		common.BizError(c, "删除模版失败")
		return
	}

	if err := model.DeleteTemplate(templateId); err != nil {
		common.BizError(c, "删除模版失败")
		return
	}

	common.OK(c)
}

func TemplateList(c *gin.Context) {
	list, err := model.QueryTaskTemplateList()
	if err != nil {
		common.BizError(c, "查询模版列表失败")
		return
	}

	common.OKData(c, list)
}
